package com.mpgame.common.network;

import com.mpgame.common.proto.GamePacket;
import com.mpgame.common.utils.Log;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;

import java.util.function.Supplier;

public class NetTcpServer {
    private final int port;

    public NetTcpServer(int port) {
        this.port = port;
    }

    /**
     * 打开服务器
     */
    public void start(Supplier<ChannelInboundHandlerAdapter> handlerSupplier) throws InterruptedException{
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try{
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .childHandler(new ChannelInitializer<Channel>(){
                @Override
                protected void initChannel(Channel ch){
                    ch.pipeline()
                     .addLast(new ProtobufVarint32FrameDecoder())
                     .addLast(new ProtobufDecoder(GamePacket.getDefaultInstance()))
                     .addLast(new ProtobufVarint32LengthFieldPrepender())
                     .addLast(new ProtobufEncoder())
                     .addLast(new ChannelDuplexHandler(){
                        @Override
                        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause){
                            Log.err("连接异常：" + cause.getMessage());
                            ctx.close();
                        }
                     })
                     .addLast(handlerSupplier.get());
                }
             });

             ChannelFuture f = b.bind(port).sync();
             Log.info("服务器启动成功，端口号：" + port);
             f.channel().closeFuture().sync();
        }
        finally{
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
